﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Reflection;
using System.Globalization;

namespace Light.Utility
{
    public class NetHelper
    {

        private NetHelper()
        {
        }

        private static TcpClient CreateTcpClient(Uri target, IWebProxy proxy, int timeout)
        {
            TcpClient client;
            if (proxy != null)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(target);
                request.Method = "CONNECT";
                request.Proxy = proxy;
                request.ServicePoint.Expect100Continue = false;
                Stream responseStream = request.GetResponse().GetResponseStream();
                object obj2 = responseStream.GetType().GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(responseStream, null);
                if (obj2 != null)
                {
                    obj2 = obj2.GetType().GetProperty("NetworkStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj2, null);
                    if (obj2 is NetworkStream)
                    {
                        obj2 = obj2.GetType().GetProperty("Socket", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj2, null);
                        if (obj2 is Socket)
                        {
                            client = new TcpClient
                            {
                                Client = (Socket)obj2
                            };
                        }
                    }
                }
                throw new ArgumentException("proxy");
            }
            client = new TcpClient();
            if ((client != null) && (timeout >= 0))
            {
                client.SendTimeout = client.ReceiveTimeout = timeout;
            }
            return client;
        }

        public static void FtpDownload(Uri uri, string localFile)
        {
            FtpDownload(uri, localFile, null, null);
        }

        public static void FtpDownload(Uri uri, string localFile, string user, string password)
        {
            if (uri.Scheme != Uri.UriSchemeFtp)
            {
                throw new NotSupportedException();
            }
            if (string.IsNullOrEmpty(localFile))
            {
                throw new ArgumentException("localFile");
            }
            FileInfo info = new FileInfo(localFile);
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
            request.Method = "RETR";
            request.UseBinary = true;
            if (!string.IsNullOrEmpty(user))
            {
                request.Credentials = new NetworkCredential(user, password);
            }
            using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
            {
                try
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        long contentLength = response.ContentLength;
                        int count = 0x800;
                        using (FileStream stream2 = new FileStream(info.FullName, FileMode.Create))
                        {
                            byte[] buffer = new byte[count];
                            for (int i = stream.Read(buffer, 0, count); i > 0; i = stream.Read(buffer, 0, count))
                            {
                                stream2.Write(buffer, 0, i);
                            }
                            stream2.Close();
                        }
                        stream.Close();
                    }
                }
                finally
                {
                    response.Close();
                }
            }
        }

        public static string HttpRequest(Uri uri, string method, string data)
        {
            return HttpRequest(uri, method, data, Encoding.ASCII, null);
        }

        public static string HttpRequest(Uri uri, string method, string data, Encoding encoding)
        {
            return HttpRequest(uri, method, data, encoding, null);
        }

        public static string HttpRequest(Uri uri, string method, string data, Encoding encoding, IDictionary<HttpRequestHeader, string> head)
        {
            return HttpRequest(uri, method, data, encoding, head, -1);
        }

        public static string HttpRequest(Uri uri, string method, string data, Encoding encoding, IDictionary<HttpRequestHeader, string> head, int timeout)
        {
            return HttpRequest(uri, method, data, encoding, head, timeout, null);
        }

        public static string HttpRequest(Uri uri, string method, string data, Encoding encoding, IDictionary<HttpRequestHeader, string> head, int timeout, IWebProxy proxy)
        {
            string str2;
            if (uri.Scheme != Uri.UriSchemeHttp)
            {
                throw new NotSupportedException();
            }
            if (string.IsNullOrEmpty(method))
            {
                method = "GET";
            }
            else
            {
                method = method.ToUpper();
            }
            if (head == null)
            {
                head = new Dictionary<HttpRequestHeader, string>();
            }
            if (!head.ContainsKey(HttpRequestHeader.Connection))
            {
                head.Add(HttpRequestHeader.Connection, "close");
            }
            if (!head.ContainsKey(HttpRequestHeader.CacheControl))
            {
                head.Add(HttpRequestHeader.CacheControl, "no-cache");
            }
            if (!head.ContainsKey(HttpRequestHeader.Accept))
            {
                head.Add(HttpRequestHeader.Accept, "*/*");
            }
            if (!head.ContainsKey(HttpRequestHeader.AcceptLanguage))
            {
                head.Add(HttpRequestHeader.AcceptLanguage, "zh-CN");
            }
            if (!head.ContainsKey(HttpRequestHeader.UserAgent))
            {
                head.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible;)");
            }
            if (data != null)
            {
                head[HttpRequestHeader.ContentLength] = encoding.GetByteCount(data).ToString();
            }
            else
            {
                head.Remove(HttpRequestHeader.ContentLength);
            }
            DateTimeFormatInfo dateTimeFormat = new CultureInfo("en-US", false).DateTimeFormat;
            head[HttpRequestHeader.Date] = DateTime.Now.ToUniversalTime().ToString("R", dateTimeFormat);
            StringBuilder builder = new StringBuilder();
            builder.AppendFormat("{0} {1} HTTP/1.1\r\n", method, uri.PathAndQuery);
            builder.AppendFormat("Host: {0}\r\n", uri.Authority);
            foreach (HttpRequestHeader header in head.Keys)
            {
                string str = head[header];
                if (!string.IsNullOrEmpty(str))
                {
                    builder.AppendFormat("{0}: {1}\r\n", StringHelper.Amead(header.ToString(), '-'), str);
                }
            }
            builder.Append("\r\n");
            if (data != null)
            {
                builder.Append(data);
            }
            using (TcpClient client = CreateTcpClient(uri, proxy, timeout))
            {
                str2 = Request(client, uri.Host, uri.Port, builder.ToString(), encoding);
            }
            if (string.IsNullOrEmpty(str2))
            {
                throw new WebException("已经成功连接远程服务器，但是服务器没有应答。", WebExceptionStatus.ReceiveFailure);
            }
            int index = str2.IndexOf("\r\n\r\n");
            if (index > 0)
            {
                index += 4;
                if ((index <= str2.Length) && IsHeads(str2.Substring(0, index - 4)))
                {
                    return str2.Substring(index);
                }
                return str2;
            }
            if (IsHeads(str2))
            {
                return string.Empty;
            }
            return str2;
        }

        public static void HttpDownload(Uri requestUri, string localFile)
        {
            FileStream fileStream;
            long position = 0;

            if (File.Exists(localFile))
            {
                fileStream = File.OpenWrite(localFile);

                position = fileStream.Length;
                fileStream.Seek(position, SeekOrigin.Current);
            }
            else
            {
                fileStream = new FileStream(localFile, FileMode.Create);
                position = 0;
            }

            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);

                if (position > 0)
                    request.AddRange(Convert.ToInt32(position));

                using (Stream stream = request.GetResponse().GetResponseStream())
                {
                    byte[] content = new byte[512];
                    int size = stream.Read(content, 0, 512);

                    while (size > 0)
                    {
                        fileStream.Write(content, 0, size);
                        size = stream.Read(content, 0, 512);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                fileStream.Close();
            }
        }

        private static bool IsHeads(string s)
        {
            if (s == null)
            {
                return false;
            }
            return s.Trim().StartsWith("HTTP/1.", StringComparison.OrdinalIgnoreCase);
        }

        public static byte[] NetworkRead(NetworkStream ns)
        {
            return NetworkRead(ns, -1);
        }

        public static byte[] NetworkRead(TcpClient client)
        {
            return NetworkRead(client, -1);
        }

        public static byte[] NetworkRead(NetworkStream ns, int size)
        {
            return ReadStream(ns, size, 0x400);
        }

        public static byte[] NetworkRead(TcpClient client, int size)
        {
            return TcpRead(client, size, false);
        }

        public static byte[] NetworkReadClose(TcpClient client)
        {
            return NetworkReadClose(client, -1);
        }

        public static byte[] NetworkReadClose(TcpClient client, int size)
        {
            return TcpRead(client, size, true);
        }

        public static void NetworkWrite(NetworkStream ns, byte[] buffer)
        {
            NetworkWrite(ns, buffer, 0, buffer.Length);
        }

        public static void NetworkWrite(TcpClient client, byte[] buffer)
        {
            NetworkWrite(client, buffer, 0, buffer.Length);
        }

        public static void NetworkWrite(NetworkStream ns, byte[] buffer, int offset, int size)
        {
            if (ns.CanWrite)
            {
                ns.Write(buffer, offset, size);
                ns.Flush();
            }
        }

        public static void NetworkWrite(TcpClient client, byte[] buffer, int offset, int size)
        {
            TcpWrite(client, buffer, 0, buffer.Length, false);
        }

        public static void NetworkWriteClose(TcpClient client, byte[] buffer)
        {
            NetworkWriteClose(client, buffer, 0, buffer.Length);
        }

        public static void NetworkWriteClose(TcpClient client, byte[] buffer, int offset, int size)
        {
            TcpWrite(client, buffer, 0, buffer.Length, true);
        }

        private static byte[] ReadStream(NetworkStream ns, int size, int bufferSize)
        {
            if (size == 0)
            {
                return new byte[0];
            }
            if ((size != -1) && (size < bufferSize))
            {
                bufferSize = size;
            }
            List<byte> list = new List<byte>(bufferSize);
            if (ns.CanRead)
            {
                int num = 0;
                byte[] buffer = new byte[bufferSize];
                do
                {
                    num = ns.Read(buffer, 0, buffer.Length);
                    if (num == buffer.Length)
                    {
                        list.AddRange(buffer);
                    }
                    else if (num > 0)
                    {
                        for (int i = 0; i < num; i++)
                        {
                            list.Add(buffer[i]);
                            if ((size != -1) && (list.Count >= size))
                            {
                                break;
                            }
                        }
                    }
                }
                while ((num != 0) & ((size == -1) || (list.Count < size)));
            }
            return list.ToArray();
        }

        private static string Request(TcpClient client, string hostName, int port, string data, Encoding encoding)
        {
            byte[] buffer2;
            byte[] bytes = encoding.GetBytes(data);
            try
            {
                client.Connect(hostName, port);
                using (NetworkStream stream = client.GetStream())
                {
                    NetworkWrite(stream, bytes);
                    buffer2 = ReadStream(stream, -1, client.ReceiveBufferSize);
                    stream.Close();
                }
            }
            finally
            {
                client.Close();
            }
            return (((buffer2 != null) && (buffer2.Length != 0)) ? encoding.GetString(buffer2) : null);
        }

        private static byte[] TcpRead(TcpClient client, int size, bool end)
        {
            if (client.Connected)
            {
                NetworkStream ns = client.GetStream();
                try
                {
                    return ReadStream(ns, size, client.ReceiveBufferSize);
                }
                finally
                {
                    if (end && (ns != null))
                    {
                        ns.Close();
                        ns.Dispose();
                    }
                    ns = null;
                }
            }
            return null;
        }

        public static string TcpRequest(string hostName, int port, string data, Encoding encoding)
        {
            return TcpRequest(hostName, port, data, encoding, -1);
        }

        public static string TcpRequest(string hostName, int port, string data, Encoding encoding, int timeout)
        {
            using (TcpClient client = CreateTcpClient(null, null, timeout))
            {
                return Request(client, hostName, port, data, encoding);
            }
        }

        private static void TcpWrite(TcpClient client, byte[] buffer, int offset, int size, bool end)
        {
            if (client.Connected)
            {
                NetworkStream ns = client.GetStream();
                try
                {
                    NetworkWrite(ns, buffer, offset, size);
                }
                finally
                {
                    if (end && (ns != null))
                    {
                        ns.Close();
                        ns.Dispose();
                    }
                    ns = null;
                }
            }
        }

        public static bool TestConnect(Uri uri)
        {
            return TestConnect(uri.Host, uri.Port);
        }

        public static bool TestConnect(string hostName, int port)
        {
            bool flag;
            using (TcpClient client = CreateTcpClient(null, null, 60))
            {
                try
                {
                    client.Connect(hostName, port);
                    flag = client.Connected;
                }
                catch
                {
                    flag = false;
                }
                finally
                {
                    client.Close();
                }
            }
            return flag;
        }
    }

}
